﻿using Avalonia;
using Avalonia.Media;
using FantomNext.Helpers;
using FantomNext.Shared;
using FantomNext.Views;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FantomNext.Presenters
{
    //VisualManage
    // canvas 和 图形呈现的选框，主要解决视图和缩放相关的内容。
    public partial class ScenePresenter
    {

        #region props

        public double Zoom
        {
            get => _zoom;
            set
            {
                _zoom = Math.Clamp(value, 0.1, 5f);
            }
        }
        private double _zoom = 1d;

        #endregion

        #region methods

        /// <summary>
        /// 视图更改后的更新。
        /// </summary>
        /// <param name="view"></param>
        /// <param name="model"></param>
        /// <param name="rect"></param>
        private void UpdateScene(SceneEditor view, Scene model, Avalonia.Controls.Shapes.Rectangle rect)
        {
            var sceneSize = GetSceneVisualSize(view.Bounds.Width, view.Bounds.Height, model.Size.X, model.Size.Y, _zoom, 0.01);
            rect.Width = sceneSize.Width;
            rect.Height = sceneSize.Height;
            UpdateCanvasTransform();
            UpdateSelectionFrame();
        }


        /// <summary>
        /// 更新当前画布的最基本转换，用于实现整体所有图形的缩放。
        /// </summary>
        private void UpdateCanvasTransform()
        {
            var canvasVisualRect = GetSceneVisualRect();
            var view = _view;
            var canvas = view.PART_FantomCanvas;
            var transformGroup = canvas.RenderTransform as TransformGroup;

            // 画布偏移调整，和画布底框一致。
            var translateTransform = transformGroup.Children.OfType<TranslateTransform>().FirstOrDefault();
            translateTransform.X = canvasVisualRect.Left;
            translateTransform.Y = canvasVisualRect.Top;

            // 画布偏移调整，和画布底框缩放一致。
            var scale = (canvasVisualRect.Width / _model.Size.X + canvasVisualRect.Height / _model.Size.Y) / 2;
            var scaleTransform = transformGroup.Children.OfType<ScaleTransform>().FirstOrDefault();
            scaleTransform.ScaleX = scale;
            scaleTransform.ScaleY = scale;

        }

        /// <summary>
        /// 更新选框，这块内容放在了VisualManage的地方。
        /// </summary>
        private void UpdateSelectionFrame()
        {
            foreach (var selectionFrame in _selectionFrames)
            {
                VisualizeSelectionFrame(selectionFrame);
            }
        }

        /// <summary>
        /// 获得当前画布底框的可视化尺寸。
        /// </summary>
        /// <param name="editorWidth"></param>
        /// <param name="editorHeight"></param>
        /// <param name="sceneWidth"></param>
        /// <param name="sceneHeight"></param>
        /// <param name="ratio"></param>
        /// <param name="marginRatio"></param>
        /// <returns></returns>
        private Size GetSceneVisualSize(double editorWidth, double editorHeight, double sceneWidth, double sceneHeight, double ratio, double marginRatio)
        {
            // 实际参与计算的比例，marginRatio 存在的意义在 ratio = 100% 的情况下，能够在编辑器边缘留下一点空白
            // 以显示编辑器的外框。
            var visualRatio = ratio - marginRatio;

            var innerSize = RatioHelper.CalculateInnerRectangle(new Size(editorWidth, editorHeight), sceneWidth / sceneHeight);
            return innerSize * visualRatio;
        }


        /// <summary>
        /// 获得当前画布底框的可视化绘制的样子，不仅有尺寸。
        /// </summary>
        /// <returns></returns>
        public Rect GetSceneVisualRect()
        {
            var view = _view;
            var model = _model;
            var rect = view.PART_RectScene;
            var sceneSize = GetSceneVisualSize(view.Bounds.Width, view.Bounds.Height, model.Size.X, model.Size.Y, _zoom, 0.01);

            var point = new Avalonia.Point((view.Bounds.Width - sceneSize.Width) / 2, (view.Bounds.Height - sceneSize.Height) / 2);

            return new Rect(point, sceneSize);
        }


        // 可视化转换。
        public Avalonia.Point ConvertScenePointToVisualPoint(Avalonia.Point scenePoint)
        {
            var sceneView = View;
            var canvas = sceneView.PART_FantomCanvas;
            var matrix = canvas.RenderTransform.Value;
            return matrix.Transform(scenePoint);
        }

        // 可视化转换。
        public Avalonia.Point ConvertVisualPointToScenePoint(Avalonia.Point visualPoint)
        {
            var sceneView = View;
            var canvas = sceneView.PART_FantomCanvas;
            var matrix = canvas.RenderTransform.Value;
            var invertMatrix = matrix.Invert();

            return invertMatrix.Transform(visualPoint);
        }


        #endregion
    }
}
